# -*- coding: utf-8 -*-
"""
@Author：mengying
@file： views.py
@date：2023/12/19 17:53
@email: 652044581@qq.com
@desc: 
"""
from sanic.views import HTTPMethodView
from sanic.response import json as JsonResponse
from utils.myResFormat import ResultJson, ResultCode
from utils.myEncrypt import HashCipher
from utils.myTimeFormat import MyTime
from utils.myCache import Cache
from utils.myDataUtils import TreeBuilder
from api.login.captchaImage import CaptchaImage
from addict import Dict
from aredis import StrictRedis
from config import config
from database.model.user import SystemUserDao, SystemUserRoleDao
from database.model.dept import SystemDeptDao, SystemDelEnum, SystemStatusEnum
from database.model.role import SystemRoleDao, SystemRoleMenuDao
from database.model.menu import SystemMenuDao
import uuid
import itertools
import json


class CaptchaImageView(HTTPMethodView):

    async def get(self, request):
        """【系统用户】获取验证码"""
        captcha = CaptchaImage()

        # 生成验证码图片和字符串
        captcha_string, image_base64 = captcha.generate(width=120, height=40)

        res = Dict()
        uid = uuid.uuid4().hex
        res.img = image_base64
        res.uuid = uid
        res.captchaEnabled = True

        # 存入缓存
        RedisClient: StrictRedis = Cache().select('redis').current_db
        await RedisClient.set(uid, captcha_string, ex=5 * 60)

        return JsonResponse(ResultJson(ResultCode.SUCCESS, data=res.to_dict()).result)


class LoginView(HTTPMethodView):

    async def post(self, request):
        """【系统登陆】登陆"""
        data: Dict = request.json

        # 验证码账号密码
        RedisClient: StrictRedis = Cache().select('redis').current_db
        username = data.get("username", "")
        password = data.get("password", "")

        # 如果有验证码的情况,校验方式
        uid = data.get("uuid", "")
        code = data.get("code", "")

        if uid:
            authCode = await RedisClient.get(uid)
            if not authCode:
                return JsonResponse(ResultJson(ResultCode.AUTH_CODE_EXP).result)
            else:
                if str(authCode).strip() != str(code).strip():
                    return JsonResponse(ResultJson(ResultCode.AUTH_CODE_ERROR).result)

        condition = {
            "username": username,
            "password": HashCipher.md5(config.ENCRYPT_STRING + str(password))
        }
        user_data = await SystemUserDao().find_one(condition=condition)

        if not user_data:
            return JsonResponse(ResultJson(ResultCode.PASSWORD_ERROR).result)
        else:
            # 用户是否被删除
            delFlag = user_data.get("delFlag")
            if delFlag == SystemDelEnum.p1.value:
                return JsonResponse(ResultJson(ResultCode.USER_NOT_EXIST).result)

            # 用户是否被禁用
            status = user_data.get("status")
            if status == SystemStatusEnum.p1.value:
                return JsonResponse(ResultJson(ResultCode.USER_NOT_ALLOW).result)

            # 获取角色信息
            token = uuid.uuid4().hex
            userInfo = Dict()

            # 组装用户数据(部门)
            deptId = user_data["deptId"]
            userId = user_data["userId"]

            # 查询组装部门数据
            condition = {
                "deptId": deptId,
                "delFlag": SystemDelEnum.p0.value,
                "status": SystemStatusEnum.p0.value,
            }
            deptData = await SystemDeptDao().find_one(condition=condition)
            user_data["dept"] = deptData

            # 查询组装用户数据(角色)
            UserRoleData = await SystemUserRoleDao().find(condition=dict(userId=userId))

            condition = {
                "roleId": {"$in": [roleItem.get("roleId") for roleItem in UserRoleData]},
                "delFlag": SystemDelEnum.p0.value,
                "status": SystemStatusEnum.p0.value,
            }
            RoleDataList = await SystemRoleDao().find(condition=condition)
            user_data["role"] = RoleDataList

            userInfo.user = user_data
            userInfo.roles = [role.get("roleKey") for role in RoleDataList]

            # 判断是否管理员，管理员不根据数据库记录权限而拥有全部权限
            if any([role.get("roleAdmin") for role in RoleDataList]):
                userInfo.permissions = ["*:*:*"]
            else:
                # 对目录权限进行去重
                menuIdList = itertools.chain.from_iterable([RoleData.get("menuIds", []) for RoleData in RoleDataList])

                condition = {
                    "menuId": {"$in": list(set(menuIdList))},
                    "status": SystemStatusEnum.p0.value
                }

                # 查询用户的目录权限字符
                permDict = await SystemMenuDao().find(condition=condition, field=['perms'])
                userInfo.permissions = [permItem.get("perms") for permItem in permDict]

            await RedisClient.set(token, json.dumps(userInfo.to_dict()), ex=60 * 60)

            # 更新最后登陆的时间和ip
            update = dict(loginIp=request.ip, loginDate=MyTime.TimeFormat())
            await SystemUserDao().update(condition=dict(userId=userId), update=update)

            return JsonResponse(ResultJson(ResultCode.SUCCESS, data=token).result)


class GetInfoView(HTTPMethodView):

    async def get(self, request):
        """【系统登陆】获取登陆用户信息"""
        user_info = request.headers.user_info
        return JsonResponse(ResultJson(ResultCode.SUCCESS, data=user_info).result)


class GetRoutersView(HTTPMethodView):

    def routerFormat(self, MenuData):
        # 目录数据组装前端的路由格式
        container = []
        for item in MenuData:
            # 组装目录
            if item.get('menuType') == 'M':

                # 判断是否外链接
                if item.get('isFrame') == "0":
                    menuItem = {
                        "id": item.get('menuId'),
                        "parentId": item.get('parentId'),
                        "component": "Layout",
                        "hidden": bool(int(item.get('visible'))),
                        "path": item.get('path'),
                        "name": item.get('path'),
                        "meta": {
                            "icon": item.get('icon'),
                            "link": item.get('path'),
                            "noCache": bool(int(item.get('isCache'))),
                            "title": item.get('menuName'),
                        }

                    }
                else:
                    menuItem = {
                        "id": item.get('menuId'),
                        "parentId": item.get('parentId'),
                        "component": "Layout",
                        "hidden": bool(int(item.get('visible'))),
                        "path": "/" + item.get('path'),
                        "name": str(item.get('path')).capitalize(),
                        "redirect": "noRedirect",
                        "meta": {
                            "icon": item.get('icon'),
                            "link": "",
                            "noCache": bool(int(item.get('isCache'))),
                            "title": item.get('menuName'),
                        }
                    }
                container.append(menuItem)

            # 处理组件形式
            elif item.get('menuType') == 'C':
                menuItem = {
                    "id": item.get('menuId'),
                    "parentId": item.get('parentId'),
                    "component": item.get('component'),
                    "hidden": bool(int(item.get('visible'))),
                    "path": item.get('path'),
                    "name": str(item.get('path')).capitalize(),
                    "redirect": "noRedirect",
                    "meta": {
                        "icon": item.get('icon'),
                        "link": "",
                        "noCache": bool(int(item.get('isCache'))),
                        "title": item.get('menuName'),
                    }
                }
                container.append(menuItem)

        # 基础数据组装后，组装成树结构
        treeData = TreeBuilder(container).build(parentKey="parentId", ownerKey="id", topParent="0")
        return list(treeData.values()) if treeData else []

    async def get(self, request):
        """【系统登陆】获取登陆用户的路径信息"""
        user_info = request.headers.user_info

        # 获取用户的角色信息
        roleData = user_info.get("user", {}).get("role", [])

        # 根据角色和目录关系查到目录权限
        roleAdminList = [roleItem.get("roleAdmin") for roleItem in roleData]

        # 判断是否是管理员，如果是理员返回全部目录，如果不是根据角色和目录的关系返回
        if any(roleAdminList):
            MenuData = await SystemMenuDao().find(condition=dict())
        else:
            # 对角色和权限进行去重
            menuIdList = itertools.chain.from_iterable([roleItem.get("menuIds", []) for roleItem in roleData])

            # 查询用户目录
            condition = {
                "menuId": {"$in": list(set(menuIdList))},
                "status": SystemStatusEnum.p0.value
            }
            MenuData = await SystemMenuDao().find(condition=condition)

        routerInfo = self.routerFormat(MenuData)
        return JsonResponse(ResultJson(ResultCode.SUCCESS, data=routerInfo).result)


class LogoutView(HTTPMethodView):

    async def post(self, request):
        """【系统登陆】退出登录"""
        token = request.headers.user_info.get("token")
        RedisClient: StrictRedis = Cache().select('redis').current_db

        if not token:
            return JsonResponse(ResultJson(ResultCode.SUCCESS).result)

        # 删除token
        await RedisClient.delete(token)
        return JsonResponse(ResultJson(ResultCode.SUCCESS).result)
